`timescale 1ns / 1ps
/*
 Copyright 2020 Sean Xiao, jxzsxsp@qq.com
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

module instr_dec
(
    input  sys_clk,
    input  [ 31: 0 ] i_instr,

    output RV32I,

    output [ 4: 0 ] o_rs1_idx,
    output [ 4: 0 ] o_rs2_idx,
    output [ 4: 0 ] o_rd_idx,

    output [ 15: 0 ] o_instr_group,

    output [ 8: 0 ] o_opimm_instr,
    output [ 9: 0 ] o_op_instr,
    output [ 5: 0 ] o_branch_instr,
    output [ 4: 0 ] o_load_instr,
    output [ 2: 0 ] o_store_instr,
    output [ 1: 0 ] o_fence_instr,
    
    output [ 5: 0 ] o_csr_instr,
    output [11: 0 ] o_csr_addr, 
    
    output [ 4: 0 ] o_shamt,
    output [ 31: 0 ] o_I_imm,   //I-type immediate
    output [ 31: 0 ] o_S_imm,   //R-type immediate
    output [ 31: 0 ] o_B_imm,   //S-type immediate
    output [ 31: 0 ] o_J_imm,   //J-type immediate
    output [ 31: 0 ] o_U_imm,    //U-type immediate
    output [ 31: 0 ] o_csr_imm,
//output [31:0]   o_pc
    output          o_mret,
    output          o_ecall,
    output          o_ebreak,
    output          o_dret,
    output          o_wfi

);

//===============================================================================
// riscv instruction basic decode OP DECODE 
wire [ 6: 0 ] opcode = i_instr[ 6: 0 ];
wire [ 2: 0 ] funct3 = i_instr[ 14: 12 ];
wire [ 6: 0 ] funct7 = i_instr[ 31: 25 ];

assign RV32I = ( opcode[ 1: 0 ] == 2'b11 ) && ( opcode[ 4: 2 ] != 3'b111 );

//register index decode
assign o_rd_idx  = i_instr[ 11: 7 ];
assign o_rs1_idx = i_instr[ 19: 15 ];
assign o_rs2_idx = i_instr[ 24: 20 ];
//===============================================================================
// decode opcode [6:0]
wire LUI      = ( opcode[ 6: 0 ] == 7'b011_0111 );     // TYPE U lui
wire AUIPC    = ( opcode[ 6: 0 ] == 7'b001_0111 );     // TYPE U auipc

wire JAL      = ( opcode[ 6: 0 ] == 7'b110_1111 );     // TYPE J jal
wire JALR     = ( opcode[ 6: 0 ] == 7'b110_0111 );     // TYPE I jalr

wire BRANCH   = ( opcode[ 6: 0 ] == 7'b110_0011 );     // TYPE B 

wire LOAD     = ( opcode[ 6: 0 ] == 7'b000_0011 );     // TYPE I load
wire STORE    = ( opcode[ 6: 0 ] == 7'b010_0011 );     // YTPE S store

wire OP_IMM   = ( opcode[ 6: 0 ] == 7'b001_0011 );     // TYPE I operator
wire OP       = ( opcode[ 6: 0 ] == 7'b011_0011 );     // TYPE R operator

wire FENCE    = ( opcode[ 6: 0 ] == 7'b000_1111 );     // TYPE I fence
wire CSR      = ( opcode[ 6: 0 ] == 7'b111_0011 );     // TYPE I csr



assign o_instr_group = { FENCE, CSR, STORE, LOAD, BRANCH, JALR, JAL, AUIPC, LUI, OP, OP_IMM };

//===============================================================================
// funct3 decode
wire funct3_0 = ( funct3 == 3'b000 );
wire funct3_1 = ( funct3 == 3'b001 );
wire funct3_2 = ( funct3 == 3'b010 );
wire funct3_3 = ( funct3 == 3'b011 );
wire funct3_4 = ( funct3 == 3'b100 );
wire funct3_5 = ( funct3 == 3'b101 );
wire funct3_6 = ( funct3 == 3'b110 );
wire funct3_7 = ( funct3 == 3'b111 );
//===============================================================================
//funct7 decode
wire funct7_0  = ( funct7 == 7'b0 );
wire funct7_20 = ( funct7 == 7'b010_0000 );
//===============================================================================
//imm & shamt decode

assign o_I_imm = { { 20{ i_instr[ 31 ] } } , i_instr[ 31: 20 ] }; //addi/slti/sltiu/andi/ori/xori, lw/lh/lhu/lb/lbu, JALR, SLLI/SRLi/SRAI

assign o_S_imm = { { 20{ i_instr[ 31 ] } }, i_instr[ 31: 25 ], i_instr[ 11: 7 ] }; //s-type instruction, provide imm or store instruction

assign o_B_imm = { { 19{ i_instr[ 31 ] } }, i_instr[ 31 ], i_instr[ 7 ], i_instr[ 30: 25 ], i_instr[ 11: 8 ], 1'b0 };

assign o_U_imm = { i_instr[ 31: 12 ], 12'b0 };

assign o_J_imm = { { 11{ i_instr[ 31 ] } }, i_instr[ 31 ], i_instr[ 19: 12 ], i_instr[ 20 ], i_instr[ 30: 21 ], 1'b0 }; //for JAL,

assign o_shamt = i_instr[ 24: 20 ];

assign o_csr_imm   = {27'b0,i_instr[19:15]};

//===============================================================================
// instruction decode for I-type operator 7'b001_0011
wire rv32i_addi   = OP_IMM & funct3_0;
wire rv32i_slti   = OP_IMM & funct3_2;
wire rv32i_sltiu  = OP_IMM & funct3_3;
wire rv32i_xori   = OP_IMM & funct3_4;
wire rv32i_ori    = OP_IMM & funct3_6;
wire rv32i_andi   = OP_IMM & funct3_7;

wire rv32i_slli   = OP_IMM & funct3_1 ;
wire rv32i_srli   = OP_IMM & funct3_5 & funct7_0;
wire rv32i_srai   = OP_IMM & funct3_5 & funct7_20;

assign o_opimm_instr = { rv32i_srai, rv32i_srli, rv32i_slli,
                         rv32i_andi, rv32i_ori, rv32i_xori,
                         rv32i_sltiu, rv32i_slti, rv32i_addi };

//===============================================================================
//instruction decode for R-type

wire rv32i_add    = OP & funct3_0 & funct7_0;
wire rv32i_sub    = OP & funct3_0 & funct7_20;

wire rv32i_sll    = OP & funct3_1 & funct7_0;

wire rv32i_slt    = OP & funct3_2 & funct7_0;
wire rv32i_sltu   = OP & funct3_3 & funct7_0;
wire rv32i_xor    = OP & funct3_4 & funct7_0;

wire rv32i_srl    = OP & funct3_5 & funct7_0;
wire rv32i_sra    = OP & funct3_5 & funct7_20;

wire rv32i_or     = OP & funct3_6 & funct7_0;
wire rv32i_and    = OP & funct3_7 & funct7_0;

assign o_op_instr = { rv32i_sra, rv32i_sub, rv32i_srl,
                      rv32i_sll, rv32i_xor, rv32i_or,
                      rv32i_and, rv32i_sltu, rv32i_slt,
                      rv32i_add };
//===============================================================================
//instruction for conditional branch
wire rv32i_beq    = BRANCH & funct3_0;
wire rv32i_bne    = BRANCH & funct3_1;
wire rv32i_blt    = BRANCH & funct3_4;
wire rv32i_bltu   = BRANCH & funct3_6;
wire rv32i_bgt    = BRANCH & funct3_5;
wire rv32i_bgtu   = BRANCH & funct3_7;

assign o_branch_instr = { rv32i_bgtu, rv32i_bgt, rv32i_bltu,
                          rv32i_blt, rv32i_bne, rv32i_beq };

//===============================================================================
// memory operation load/store
wire rv32i_lw     = LOAD & funct3_2;
wire rv32i_lh     = LOAD & funct3_1;
wire rv32i_lhu    = LOAD & funct3_5;
wire rv32i_lb     = LOAD & funct3_0;
wire rv32i_lbu    = LOAD & funct3_4;

wire rv32i_sw = STORE & funct3_2;
wire rv32i_sh = STORE & funct3_1;
wire rv32i_sb = STORE & funct3_0;


assign o_load_instr  = { rv32i_lbu, rv32i_lb, rv32i_lhu, rv32i_lh, rv32i_lw };
assign o_store_instr = { rv32i_sb, rv32i_sh, rv32i_sw };

//===============================================================================
//instruction for fence
wire rv32i_fence    = FENCE & funct3_0;
wire rv32i_fence_i  = FENCE & funct3_1;

assign o_fence_instr = {rv32i_fence_i, rv32i_fence };

//===============================================================================
//instruction for csr

wire rv32i_csrrw    = CSR & funct3_1;
wire rv32i_csrrs    = CSR & funct3_2;
wire rv32i_csrrc    = CSR & funct3_3;
wire rv32i_csrrwi   = CSR & funct3_5;
wire rv32i_csrrsi   = CSR & funct3_6;
wire rv32i_csrrci   = CSR & funct3_7;

assign o_csr_instr = {  rv32i_csrrci, rv32i_csrrsi, rv32i_csrrwi, 
                        rv32i_csrrc,  rv32i_csrrs,  rv32i_csrrw};


assign o_csr_addr = i_instr[ 31: 20 ];
//===============================================================================
// System Instructions
assign o_ecall    = CSR & funct3_0 & (i_instr[31:20] == 12'b0000_0000_0000);
assign o_ebreak   = CSR & funct3_0 & (i_instr[31:20] == 12'b0000_0000_0001);
assign o_mret     = CSR & funct3_0 & (i_instr[31:20] == 12'b0011_0000_0010);
assign o_dret     = CSR & funct3_0 & (i_instr[31:20] == 12'b0111_1011_0010);
assign o_wfi      = CSR & funct3_0 & (i_instr[31:20] == 12'b0001_0000_0101);


endmodule
